﻿using System.Runtime.InteropServices;
using System.Threading;
namespace ZXW.DotNet.Common.Basic.Network.Tcp
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Collections;
    using System.Net.Sockets;
    using System.Net;
    using System.Diagnostics;
    /// <summary>
    /// 通讯服务器
    /// </summary>
    public class ComServer
    {
        #region 字段
        /// <summary>
        /// 默认的服务器最大连接客户端端数据
        /// </summary>
        public const int DefaultMaxClient = 100;
        /// <summary>
        /// 接收数据缓冲区大小64K
        /// </summary>
        public const int DefaultBufferSize = 5 * 1024;
        /// <summary>
        /// 服务器使用端口
        /// </summary>
        private int _port;
        /// <summary>
        /// 服务器允许的最大客户端连接数目
        /// </summary>
        private int _maxClient;
        /// <summary>
        /// 服务器运行状态
        /// </summary>
        private bool _isRun;
        /// <summary>
        /// 接收缓冲区
        /// </summary>
        private byte[] _recvDataBuffer;
        /// <summary>
        /// 服务器使用的异步Socket类,
        /// </summary>
        private Socket _svrSock;
        /// <summary>
        /// 保存所有客户端会话的哈希表
        /// </summary>
        private Hashtable _sessionTable;
        /// <summary>
        /// 当前的连接的客户端数
        /// </summary>
        private int _clientCount;

        private bool _sendBusy;

        #endregion

        #region 事件

        /// <summary>
        /// 客户端建立连接事件
        /// </summary>
        public event GenericHandler<object, CommunicationEventArgs> ClientConnect;
        /// <summary>
        /// 客户端关闭事件
        /// </summary>
        public event GenericHandler<object, CommunicationEventArgs> ClientClose;
        /// <summary>
        /// 服务器已满事件
        /// </summary>
        public event GenericHandler<object, CommunicationEventArgs> ServerFull;

        public event GenericHandler<object, CommunicationEventArgs> RecviveData;

        private void OnClientConnect(CommunicationEventArgs e)
        {
            if (ClientConnect != null)
                ClientConnect(this, e);
        }

        private void OnClientClose(CommunicationEventArgs e)
        {
            if (ClientClose != null)
                ClientClose(this, e);
        }

        private void OnServerFull(CommunicationEventArgs e)
        {
            if (ServerFull != null)
                ServerFull(this, e);
        }

        private void OnReceiveData(CommunicationEventArgs e)
        {
            if (RecviveData != null)
                RecviveData(this, e);
        }
        #endregion

        #region 构造函数
        /// <summary>
        /// 构造函数(默认使用Default编码方式和DefaultMaxClient(100)个客户端的容量)
        /// </summary>
        /// <param name="port">服务器端监听的端口号</param>
        public ComServer(int port)
            : this(port, DefaultMaxClient)
        {
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="port">服务器端口</param>
        /// <param name="maxClient">客户端的容量</param>
        public ComServer(int port, int maxClient)
        {
            _port = port;
            _maxClient = maxClient;
        }
        #endregion

        #region 属性
        /// <summary>
        /// 服务器Socket对象
        /// </summary>
        public Socket ServerSocket
        {
            get
            {
                return _svrSock;
            }
        }

        public int Port
        {
            get
            {
                return _port;
            }
            set
            {
                _port = value;
            }
        }
        /// <summary>
        /// 客户端会话数组
        /// </summary>
        public Hashtable SessionTable
        {
            get
            {
                return _sessionTable;
            }
        }

        public Dictionary<string, string> SessionDic
        {
            get
            {
                Dictionary<string, string> sessionDic = new Dictionary<string, string>();

                foreach (Session client in _sessionTable.Values)
                {
                    sessionDic.Add(client.ClientSocket.RemoteEndPoint.ToString(), client.ID.ToString());
                }

                return sessionDic;
            }
        }
        /// <summary>
        /// 服务器可以容纳客户端最大值
        /// </summary>
        public int Capacity
        {
            get
            {
                return _maxClient;
            }
        }
        /// <summary>
        /// 当前连接数
        /// </summary>
        public int SessionCount
        {
            get
            {
                return _clientCount;
            }
        }
        /// <summary>
        /// 服务器运行状态
        /// </summary>
        public bool IsRun
        {
            get
            {
                return _isRun;
            }
        }

        public bool SendBusy
        {
            get
            {
                return _sendBusy;
            }
        }
        #endregion

        public virtual void Start()
        {
            if(_isRun )
                throw (new ApplicationException("服务器已经运行"));
            _sessionTable = new Hashtable(53);
            _recvDataBuffer = new byte[DefaultBufferSize];
            _svrSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint iep = new IPEndPoint(IPAddress.Any, _port);
            _svrSock.Bind(iep);
            //开始监听
            _svrSock.Listen(5);
            //设置异步方法接受客户端连接
            _svrSock.BeginAccept(new AsyncCallback(AcceptConn), _svrSock);
            _isRun = true;
        }

        /// <summary>
        /// 客户端连接处理函数
        /// </summary>
        /// <param name="iar">欲建立服务器连接的Socket对象</param>
        protected virtual void AcceptConn(IAsyncResult iar)
        {
            //如果服务器停止了服务,就不能再接收新的客户端
            if (!_isRun)
            {
                return;
            }
            //接受一个客户端的连接请求
            Socket oldserver = (Socket)iar.AsyncState;
            Socket client = oldserver.EndAccept(iar);
            //检查是否达到最大的允许的客户端数目
            if (_clientCount == _maxClient)
            {
                //服务器已满,发出通知
                OnServerFull( new CommunicationEventArgs(new Session(client)));
            }
            else
            {
                Session newSession = new Session(client);
                _sessionTable.Add(newSession.ID, newSession);

                //客户端引用计数+1
                _clientCount++;
                //开始接受来自该客户端的数据
                client.BeginReceive(_recvDataBuffer, 0, _recvDataBuffer.Length, SocketFlags.None,
                 new AsyncCallback(ReceiveData), client);
                //新的客户段连接,发出通知
                OnClientConnect(new CommunicationEventArgs(newSession));
            }
            //继续接受客户端
            _svrSock.BeginAccept(new AsyncCallback(AcceptConn), _svrSock);
        }


        /// <summary>
        /// 接受数据完成处理函数，异步的特性就体现在这个函数中，
        /// 收到数据后，会自动解析为字符串报文
        /// </summary>
        /// <param name="iar">目标客户端Socket</param>
        protected virtual void ReceiveData(IAsyncResult iar)
        {
            Socket client = (Socket)iar.AsyncState;
            try
            {
                //如果两次开始了异步的接收,所以当客户端退出的时候,会两次执行EndReceive
                int recv = client.EndReceive(iar);
                if (recv == 0)
                {
                    //正常的关闭
                    CloseClient(client, ExitType.NormalExit);
                    return;
                }

                //发布收到数据的事件
                if (RecviveData != null)
                {
                    Session sendDataSession = FindSession(client);
                    ICloneable copySession = (ICloneable)sendDataSession;
                    Session clientSession = (Session)copySession.Clone();
                    byte[] data = new byte[recv];
                    Array.Copy(_recvDataBuffer, 0, data, 0, recv);
                    clientSession.Data = data;
                    OnReceiveData(new CommunicationEventArgs(clientSession));
                }
                //end of if(RecvData!=null)
                //继续接收来自来客户端的数据
                client.BeginReceive(_recvDataBuffer, 0, _recvDataBuffer.Length, SocketFlags.None,
                 new AsyncCallback(ReceiveData), client);
            }
            catch (SocketException ex)
            {
                //客户端退出
                if (10054 == ex.ErrorCode)
                {
                    //客户端强制关闭
                    CloseClient(client, ExitType.ExceptionExit);
                }

            }
            catch (ObjectDisposedException ex)
            {
                //当调用CloseSession()时,会结束数据接收,但是数据接收
                //处理中会调用int recv = client.EndReceive(iar);
                //就访问了CloseSession()已经处置的对象
                if (ex != null)
                {
                    ex = null;
                }
            }

        }

        /// <summary>
        /// 关闭一个客户端Socket,首先需要关闭Session
        /// </summary>
        /// <param name="client">目标Socket对象</param>
        /// <param name="exitType">客户端退出的类型</param>
        protected virtual void CloseClient(Socket client, ExitType exitType)
        {
            Debug.Assert(client != null);
            //查找该客户端是否存在,如果不存在,抛出异常
            Session closeClient = FindSession(client);

            closeClient.TypeOfExit = exitType;
            if (closeClient != null)
            {
                CloseSession(closeClient);
            }
            else
            {
                throw (new ApplicationException("需要关闭的Socket对象不存在"));
            }
        }

        /// <summary>
        /// 发送数据完成处理函数
        /// </summary>
        /// <param name="iar">目标客户端Socket</param>
        protected virtual void SendDataEnd(IAsyncResult iar)
        {
            try
            {
                Socket client = (Socket)iar.AsyncState;
                int sent = client.EndSend(iar);
                _sendBusy = false;
            }
            catch (Exception ex)
            {
                Debug.WriteLine("SendDataEnd" + ex.Message);
                _sendBusy = false;
            }
        }

        /// <summary>
        /// 通过Socket对象查找Session对象
        /// </summary>
        /// <param name="client"></param>
        /// <returns>找到的Session对象,如果为null,说明并不存在该回话</returns>
        private Session FindSession(Socket client)
        {
            SessionId id = new SessionId((int)client.Handle);
            return (Session)_sessionTable[id];
        }
        /// <summary>
        /// 关闭一个与客户端之间的会话
        /// </summary>
        /// <param name="closeClient">需要关闭的客户端会话对象</param>
        public virtual void CloseSession(Session closeClient)
        {
            Debug.Assert(closeClient != null);
            if (closeClient != null)
            {
                closeClient.Data = null;
                _sessionTable.Remove(closeClient.ID);
                _clientCount--;

                //客户端强制关闭链接             
                OnClientClose(new CommunicationEventArgs(closeClient));
                closeClient.Close();
            }
        }

        /// <summary>
        /// 关闭所有的客户端会话,与所有的客户端连接会断开
        /// </summary>
        public virtual void CloseAllClient()
        {
            foreach (Session client in _sessionTable.Values)
            {
                client.Close();
            }
            _sessionTable.Clear();
        }

        /// <summary>
        /// 发送字节集数据
        /// </summary>
        /// <param name="recvDataClient"></param>
        /// <param name="bytes"></param>
        public virtual void Send(Session recvDataClient,byte[] bytes)
        {
            _sendBusy = true;
            recvDataClient.ClientSocket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None,
             new AsyncCallback(SendDataEnd), recvDataClient.ClientSocket);
        }

        /// <summary>
        /// 停止服务器程序,所有与客户端的连接将关闭
        /// </summary>
        public virtual void Stop()
        {
            if (!_isRun)
            {
                throw (new ApplicationException("TcpServer已经停止"));
            }
            //这个条件语句，一定要在关闭所有客户端以前调用
            //否则在EndConn会出现错误
            _isRun = false;
            //关闭数据连接,负责客户端会认为是强制关闭连接
            if (_svrSock.Connected)
            {
                _svrSock.Shutdown(SocketShutdown.Both);
            }
            CloseAllClient();
            //清理资源
            _svrSock.Close();

            _sessionTable = null;

        }
    }
}
